using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using SG3L_RAG.Application.DTOs;
using SG3L_RAG.Application.Interfaces;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace SG3L_RAG.Application.Services;

/// <summary>
/// JWT服务实现
/// </summary>
public class JwtService : IJwtService
{
    private readonly JwtOptions _jwtOptions;
    private readonly IUserService _userService;
    private readonly TokenValidationParameters _tokenValidationParameters;

    public JwtService(IOptions<JwtOptions> jwtOptions, IUserService userService)
    {
        _jwtOptions = jwtOptions.Value;
        _userService = userService;
        
        _tokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = _jwtOptions.Issuer,
            ValidAudience = _jwtOptions.Audience,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtOptions.Key)),
            ClockSkew = TimeSpan.Zero
        };
    }

    public async Task<LoginResponseDto> GenerateTokenAsync(UserInfoDto user)
    {
        var claims = new List<Claim>
        {
            new(ClaimTypes.NameIdentifier, user.Id.ToString()),
            new(ClaimTypes.Name, user.Username),
            new(ClaimTypes.Email, user.Email),
            new(ClaimTypes.Role, user.Role),
            new("phone_number", user.PhoneNumber),
            new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
            new(JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64)
        };

        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtOptions.Key));
        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

        var expiresAt = DateTime.UtcNow.AddHours(_jwtOptions.ExpiryInHours);

        var token = new JwtSecurityToken(
            issuer: _jwtOptions.Issuer,
            audience: _jwtOptions.Audience,
            claims: claims,
            expires: expiresAt,
            signingCredentials: creds
        );

        var tokenString = new JwtSecurityTokenHandler().WriteToken(token);

        return await Task.FromResult(new LoginResponseDto
        {
            Token = tokenString,
            TokenType = "Bearer",
            ExpiresAt = expiresAt,
            User = user
        });
    }

    public async Task<TokenValidationResponseDto> ValidateTokenAsync(string token)
    {
        try
        {
            if (string.IsNullOrWhiteSpace(token))
            {
                return new TokenValidationResponseDto
                {
                    IsValid = false,
                    ErrorMessage = "Token不能为空"
                };
            }

            var tokenHandler = new JwtSecurityTokenHandler();
            ClaimsPrincipal principal;
            SecurityToken validatedToken;
            try
            {
                principal = tokenHandler.ValidateToken(token, _tokenValidationParameters, out validatedToken);
            }
            catch (Exception ex)
            {
                return new TokenValidationResponseDto
                {
                    IsValid = false,
                    ErrorMessage = $"Token验证失败: {ex.Message}"
                };
            }

            if (validatedToken is not JwtSecurityToken jwtToken ||
                !jwtToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase))
            {
                return new TokenValidationResponseDto
                {
                    IsValid = false,
                    ErrorMessage = "Token格式无效"
                };
            }

            var user = GetUserFromClaims(principal.Claims);
            return await Task.FromResult(new TokenValidationResponseDto
            {
                IsValid = true,
                User = user
            });
        }
        catch (SecurityTokenExpiredException)
        {
            return new TokenValidationResponseDto
            {
                IsValid = false,
                ErrorMessage = "Token已过期"
            };
        }
        catch (SecurityTokenException ex)
        {
            return new TokenValidationResponseDto
            {
                IsValid = false,
                ErrorMessage = $"Token验证失败: {ex.Message}"
            };
        }
        catch (Exception ex)
        {
            return new TokenValidationResponseDto
            {
                IsValid = false,
                ErrorMessage = $"验证过程中发生错误: {ex.Message}"
            };
        }
    }

    public async Task<UserInfoDto?> GetUserFromTokenAsync(string token)
    {
        var validation = await ValidateTokenAsync(token);
        return validation.IsValid ? validation.User : null;
    }

    public UserInfoDto? GetUserFromClaims(IEnumerable<Claim> claims)
    {
        try
        {
            var claimsList = claims.ToList();
            
            var userIdClaim = claimsList.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier)?.Value;
            var usernameClaim = claimsList.FirstOrDefault(x => x.Type == ClaimTypes.Name)?.Value;
            var emailClaim = claimsList.FirstOrDefault(x => x.Type == ClaimTypes.Email)?.Value;
            var roleClaim = claimsList.FirstOrDefault(x => x.Type == ClaimTypes.Role)?.Value;
            var phoneClaim = claimsList.FirstOrDefault(x => x.Type == "phone_number")?.Value;

            if (string.IsNullOrWhiteSpace(userIdClaim) || !Guid.TryParse(userIdClaim, out var userId))
                return null;

            return new UserInfoDto
            {
                Id = userId,
                Username = usernameClaim ?? string.Empty,
                Email = emailClaim ?? string.Empty,
                Role = roleClaim ?? string.Empty,
                PhoneNumber = phoneClaim ?? string.Empty,
                Avatar = string.Empty, // Claims中没有Avatar信息，设置为空
                CreatedAt = DateTime.UtcNow // 这里可以从Claims中获取，或者从数据库查询
            };
        }
        catch
        {
            return null;
        }
    }

    public async Task<LoginResponseDto?> RefreshTokenAsync(string token)
    {
        try
        {
            var validation = await ValidateTokenAsync(token);
            if (!validation.IsValid || validation.User == null)
                return null;

            // 从数据库重新获取用户信息，确保数据是最新的
            var user = await _userService.GetByIdAsync(validation.User.Id);
            if (user == null)
                return null;

            var userDto = new UserInfoDto
            {
                Id = user.Id,
                Username = user.Username,
                Email = user.Email,
                Role = user.Role,
                PhoneNumber = user.PhoneNumber,
                Avatar = user.Avatar, // 添加Avatar字段
                CreatedAt = user.CreatedAt
            };

            return await GenerateTokenAsync(userDto);
        }
        catch
        {
            return null;
        }
    }
}
